package com.jason.library.asm;


import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

/**
 * @author ChenBaoyang
 * @description: 自定义ClassVisitor-用于添加
 * @date 2021/11/23 16:43
 */
public class AddTimerClassVisitor extends ClassVisitor {

    private String mOwner;

    public AddTimerClassVisitor(int api, ClassVisitor classVisitor) {
        super(api, classVisitor);
    }

    @Override
    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
        super.visit(version, access, name, signature, superName, interfaces);
        mOwner = name;
        System.out.println("name = "+name);
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
        MethodVisitor oldMethodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions);

        if(oldMethodVisitor != null && !name.equals("<init>")) {
            MethodVisitor newMethodVisitor = new MethodVisitor(api, oldMethodVisitor){
                /**
                 * 方法开始,此处可在方法开始插入字节码
                 */
                @Override
                public void visitCode() {
                    mv.visitCode();

                    // 原型：timer = timer - System.currentTimeMillis();
                    // timer入栈
                    mv.visitFieldInsn(Opcodes.GETSTATIC, mOwner,"timer","J");
                    // System.currentTimeMillis()入栈
                    mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System",
                            "currentTimeMillis","()J", false);
                    // 减法操作
                    mv.visitInsn(Opcodes.LSUB);
                    // 获取 timer
                    mv.visitFieldInsn(Opcodes.PUTSTATIC, mOwner, "timer","J");
                }

                /**
                 * 指令操作,这里可以判断拦截return,并在方法尾部插入字节码
                 */
                @Override
                public void visitInsn(int opcode) {
                    if((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) {
                        // 原型：timer = timer + System.currentTimeMillis();
                        // timer入栈
                        mv.visitFieldInsn(Opcodes.GETSTATIC, mOwner, "timer","J");
                        // System.currentTimeMillis()入栈
                        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System",
                                "currentTimeMillis","()J", false);
                        // 加法
                        mv.visitInsn(Opcodes.LADD);
                        mv.visitFieldInsn(Opcodes.PUTSTATIC, mOwner,"timer","J");

                        // 用来将常量，入栈：Float、Integer、String等等
                        //mv.visitLdcInsn("1111");
                        //mv.visitInsn(Opcodes.POP);
                    }
                    mv.visitInsn(opcode);

                }
            };
            return newMethodVisitor;
        }
        return oldMethodVisitor;

    }


    @Override
    public void visitEnd() {
        FieldVisitor fv = cv.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC,
                "timer", "J", null, null);
        if(fv != null) {
            fv.visitEnd();
        }
        cv.visitEnd();
    }
}
